#include "CApp.h"
#include "CNetwork.h"
#include "CCommand.h"
#include "CConsole.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "CSendMess.h"
#include <pthread.h>

extern pthread_mutex_t mutex;
extern pthread_mutex_t MX_RWNet;
extern pthread_mutex_t MX_RWMess;

typedef agg::glyph_raster_bin<agg::rgba8> glyph_gen;
extern CConsole console;
extern CNetwork *net;
extern std::vector< CSendMess* > v_sendMess;

extern int i_winWidth;
extern int i_winHeight;

CApp::CApp(agg::pix_format_e format, bool flip_y) :
agg::platform_support(format, flip_y),
m_slider1(420, 10,    600, 19,    !flip_y),
m_slider2(420, 10+20, 600, 19+20, !flip_y)
{
	m_idx = -1;

	add_ctrl(m_slider1);
	add_ctrl(m_slider2);

	m_slider1.range(10.0, 200.0);
	//m_slider1.num_steps(23);
	m_slider1.value(100.0);

	m_slider2.range(10.0, 400.0);
	m_slider2.value(250.0);

	m_slider1.label("Limite Wifi=%4.3f");
	m_slider2.label("Taille salon=%4.3f");

	m_slider1.no_transform();
	m_slider2.no_transform();

	// Conteneur de ligne pour les arcs
	pg = new agg::conv_stroke<agg::path_storage>(ps);
	pg->width(2.0);

	pixf = new agg::pixfmt_bgr24(rbuf_window());

	av=0;
}


void CApp::refreshNetwork()
{
	radiusWifi = m_slider1.value();
	radiusCentre = m_slider2.value();
	double dist=200;

pthread_mutex_lock(&MX_RWNet);
	// Vider les voisins
	for(int i=0; i<net->nbNodes(); i++)
	{
		net->getNode(i)->clearNeighbours();
	}

	// Calculer les voisins
	for(int i=0; i<net->nbNodes(); i++)
	{
		for(int j=i; j<net->nbNodes(); j++)
		{
			dist = sqrt(pow((double)(net->getNode(i)->getX()-net->getNode(j)->getX()),2.0)+pow((double)(net->getNode(i)->getY()-net->getNode(j)->getY()),2.0));
			if(i!=j && dist<m_slider1.value())
			{
				net->getNode(i)->addNeighbour(net->getNode(j),dist);
				net->getNode(j)->addNeighbour(net->getNode(i),dist);
			}
		}
	}
pthread_mutex_unlock(&MX_RWNet);
	force_redraw();
}


void CApp::on_draw()
{
pthread_mutex_lock(&MX_RWNet);
	// Rcupration du buffer d'cran
	ren = new ren_base(*pixf);

	//std::cout << "1" << radiusWifi << " " << m_slider1.value() << std::endl;
	if(radiusWifi - m_slider1.value()!=0.0 || radiusCentre - m_slider2.value()!=0.0)
	{
		//std::cout << "2"  << radiusWifi << " " << m_slider1.value() << std::endl;
		radiusWifi = m_slider1.value();
		//std::cout << "3"  << radiusWifi << " " << m_slider1.value() << std::endl;
		radiusCentre = m_slider2.value();
		//printf("refresh %lf %lf\n",radiusWifi,m_slider1.value());
		//usleep(50);
		//pthread_mutex_unlock(&MX_RWNet);
		//refreshNetwork();
		//return;
	}

	// Vide l'cran
	ren->clear(agg::rgba(100,100,100));

	// Couverture salon
	for(int i=0; i<net->nbCentres();i++)
	{
		ras.reset();
		ell.init(net->getCentre(i)->getX(), net->getCentre(i)->getY(),m_slider2.value(), m_slider2.value());

		ras.add_path(ell);
		agg::render_scanlines_aa_solid(ras, sl, *ren, agg::rgba8(100,100,100,100));
	}

	// Zone Wifi
	for(int i=0; i<net->nbNodes(); i++)
	{
		ras.reset();
		ell.init(net->getNode(i)->getX(), net->getNode(i)->getY(),
			m_slider1.value(),m_slider1.value());

		ras.add_path(ell);
agg::render_scanlines_aa_solid(ras, sl, *ren, agg::rgba8(220,220,220,40));
		
	}


//printf(">4\n");
	// Arcs
					ras.reset();
				ps.remove_all();
	for(int i=0; i<net->nbNodes(); i++)
	{
		/*for(int j=i; j<net->nbNodes(); j++){
			if(i!=j && sqrt(pow((double)(net->getNode(i)->getX()-net->getNode(j)->getX()),2.0)+pow((double)(net->getNode(i)->getY()-net->getNode(j)->getY()),2.0))<m_slider1.value()){
				ras.reset();
				ps.remove_all();
				ps.move_to(net->getNode(i)->getX(), net->getNode(i)->getY());
				ps.line_to(net->getNode(j)->getX(), net->getNode(j)->getY());
				ras.add_path(pg);
				agg::render_scanlines_aa_solid(ras, sl, ren, agg::rgba8(100,110,120, 255));
			}
		}*/
		for(int j=0; j<net->getNode(i)->nbNeighbours(); j++)
		{
			if(net->getNode(i)->getNeighbour(j)->id > net->getNode(i)->id)
			{

				ps.move_to(net->getNode(i)->getX(), net->getNode(i)->getY());
				ps.line_to(net->getNode(i)->getNeighbour(j)->getX(), net->getNode(i)->getNeighbour(j)->getY());

			}
		}
	}
					ras.add_path(*pg);
				agg::render_scanlines_aa_solid(ras, sl, *ren, agg::rgba8(100,110,120, 255));

	glyph_gen glyph(0);
	glyph.font(agg::verdana12);
	agg::renderer_raster_htext_solid<ren_base, glyph_gen> rt2(*ren, glyph);
	rt2.color(agg::rgba(0,0,0));

	//printf(">3\n");
	
	// Nodes
	ras.reset();
	for(int i=0; i<net->nbNodes(); i++)
	{
		
		ell.init((int)net->getNode(i)->getX(), (int)net->getNode(i)->getY(),
			net->getNode(i)->getRadius() + net->getNode(i)->getCharge(),
			net->getNode(i)->getRadius() + net->getNode(i)->getCharge());
		ras.add_path(ell);
		
	}
	agg::render_scanlines_aa_solid(ras, sl, *ren, agg::rgba8(150,160,180, 255));

	//printf(">2\n");
	
	// Text
	for(int i=0; i<net->nbNodes(); i++)
	{
			//printf("1;;%s;;;\n",net->getNode(i)->getName());
		rt2.render_text(net->getNode(i)->getX()-5, net->getNode(i)->getY()+3, net->getNode(i)->getName(), !flip_y());
	}
	
	// Messages
	/*
	int ind=0;
	ras.reset();
	pthread_mutex_lock(&mutex);
	while(ind<v_sendMess.size()){
		//v_sendMess[ind]->m_i_time--;
		//printf("-%s-\n",line.c_str());
					
		ell.init(
			(int)v_sendMess[ind]->m_CNode_src->getX()+(v_sendMess[ind]->m_CNode_dst->getX() - v_sendMess[ind]->m_CNode_src->getX())*v_sendMess[ind]->m_i_time/v_sendMess[ind]->m_i_timeInit,
			(int)v_sendMess[ind]->m_CNode_src->getY()+(v_sendMess[ind]->m_CNode_dst->getY() - v_sendMess[ind]->m_CNode_src->getY())*v_sendMess[ind]->m_i_time/v_sendMess[ind]->m_i_timeInit,
			2,2,4);
		ras.add_path(ell);
		
		ind++;
	}
	pthread_mutex_unlock(&mutex);
	agg::render_scanlines_aa_solid(ras, sl, *ren, agg::rgba8(50,60,70, 255));
	*/

//printf(">5\n");

	// Render the controls
	agg::render_ctrl(ras, sl, *ren, m_slider1);
	agg::render_ctrl(ras, sl, *ren, m_slider2);

	// Console ------------------------------------------------------------------------------------
	rt2.color(agg::rgba(255,255,255));
	glyph.font(agg::verdana12);
	ras.reset();
	int deb = console.vconsole.size()-10;
	if(deb<0) deb = 0;
	int fin = console.vconsole.size();
	if(fin>10) fin = 10;

	/*
			gradient_func_type  gradient_func;                   // The gradient function
			agg::trans_affine   gradient_mtx = gradient_affine(10, 5, 200, (fin+1)*9+5, 100);
			interpolator_type   span_interpolator(gradient_mtx); // Span interpolator
			span_allocator_type span_allocator;                  // Span Allocator
			color_func_type     color_func(agg::rgba8(0x22, 0x22, 0x22,220), agg::rgba8(0x55, 0x55, 0x55, 220));
			span_gradient_type  span_gradient(span_interpolator, gradient_func, color_func, 0, 100);
	*/
	agg::rounded_rect shape(10, 5, 400, (fin+2)*9+5, 5);
	ras.add_path(shape);
	//agg::render_scanlines_aa(ras, sl, ren, span_allocator, span_gradient);
	render_scanlines_aa_solid(ras, sl, *ren, agg::rgba8(100,100,100, 200));

	rt2.render_text(15, 15, console.m_Current.c_str() , !flip_y());
	for(int i=0; i<fin; i++)
	{
		rt2.render_text(15, (i+1)*9+15, console.vconsole[console.vconsole.size()-1-i]->c_str() , !flip_y());
	}
	// Console ------------------------------------------------------------------------------------
pthread_mutex_unlock(&MX_RWNet);
}


void CApp::on_mouse_button_down(int x, int y, unsigned flags)
{
pthread_mutex_lock(&MX_RWNet);
	m_N_select = NULL;
	if(flags & agg::mouse_left)
	{
		m_N_select = net->getFirstNodeAt(x, y);
		if(m_N_select!=NULL)
		{
			m_dx = x - m_N_select->getX();
			m_dy = y - m_N_select->getY();
		}
	}
	//else{
	//	m_N_select = NULL;
	//}
pthread_mutex_unlock(&MX_RWNet);
}


void CApp::on_mouse_move(int x, int y, unsigned flags)
{
	if(flags & agg::mouse_left)
	{
		if(m_N_select != NULL)
		{
pthread_mutex_lock(&MX_RWNet);
			m_N_select->setX(x - m_dx);
			m_N_select->setY(y - m_dy);
pthread_mutex_unlock(&MX_RWNet);
			refreshNetwork();
		}
	}
	//else{
	//    on_mouse_button_up(x, y, flags);
	//}
}


void CApp::on_mouse_button_up(int x, int y, unsigned flags)
{
	//m_N_select = NULL;
}




void CApp::on_key(int x, int y, unsigned int key, unsigned int flags)
{
//if(key==0)return;
	KeySym low, high; 
	//KeyCode c  = XKeysymToKeycode(XOpenDisplay(NULL), key);
	//printf("%c\n",c);
	switch(key)
	{
    case agg::key_left:
    case agg::key_up:
//printf("up\n");
      console.setHistory(-1);
      refreshNetwork();
      break;
    case agg::key_page_up:
    case agg::key_right:
    case agg::key_down:
      console.setHistory(1);
      refreshNetwork();
      break;
    case agg::key_page_down:
		case 60:
			if(console.vconsole.size()>0)
				console.m_Current=*console.vconsole[console.vconsole.size()-1];
			refreshNetwork();
			break;
		case 62:
			console.m_Current="";
			refreshNetwork();
			break;
		default:

			//printf("%c\n",key);
			console.SendChar(key);
			refreshNetwork();
}
	return;
}
